import sys
parent_dir = "../pygl"
sys.path.append(parent_dir)
import OpenGL.GL as gl
import glm
import imgui
import numpy as np
from common.app_v1 import App

class LineApp(App):
    # 初始化着色器，vao vbo等
    def setupVertex(self) -> None:
        vertex_shader_code = """
        #version 450 core
        layout (location = 0) in vec3 position;
        layout (location = 1) in vec3 color;
        out vec3 vertex_color;
        void main()
        {
            gl_Position = vec4(position, 1.0);
            vertex_color = color;
        }
        """
        vertex_shader = gl.glCreateShader(gl.GL_VERTEX_SHADER)
        gl.glShaderSource(vertex_shader, vertex_shader_code)
        gl.glCompileShader(vertex_shader)
        attribute_position = 0
        attribute_color = 1

        fragment_shader_code = """
        #version 450 core
        in vec3 vertex_color;
        out vec4 fragment_color;
        void main()
        {
            fragment_color = vec4(vertex_color, 1.0);
        }
        """    
        fragment_shader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
        gl.glShaderSource(fragment_shader, fragment_shader_code)
        gl.glCompileShader(fragment_shader)

        self.program = gl.glCreateProgram()
        gl.glAttachShader(self.program, vertex_shader)
        gl.glAttachShader(self.program, fragment_shader)
        gl.glLinkProgram(self.program)
        gl.glDeleteShader(vertex_shader)
        gl.glDeleteShader(fragment_shader)

        line1_position = np.array([
            -0.8, 0.0, 0.0,
            0.8, 0.0, 0.0
        ], dtype=gl.GLfloat)
        self.line1_position_vbo = np.empty(1, dtype=gl.GLuint)
        gl.glCreateBuffers(1, self.line1_position_vbo)
        gl.glNamedBufferStorage(self.line1_position_vbo[0], line1_position.nbytes, 
                                line1_position, gl.GL_DYNAMIC_STORAGE_BIT)
        
        line1_color = np.array([ 
            1.0, 0.0, 0.0,
            1.0, 0.0, 0.0
        ], dtype=gl.GLfloat)        
        self.line1_color_vbo = np.empty(1, dtype=gl.GLuint)
        gl.glCreateBuffers(1, self.line1_color_vbo)
        gl.glNamedBufferStorage(self.line1_color_vbo[0], line1_color.nbytes, 
                                line1_color, gl.GL_DYNAMIC_STORAGE_BIT)

        self.vao1 = np.empty(1, dtype=gl.GLuint)
        gl.glCreateVertexArrays(1, self.vao1)        
        line1_position_binding_point = 4
        gl.glVertexArrayVertexBuffer(self.vao1[0], line1_position_binding_point, 
                    self.line1_position_vbo[0], 0, 3 * gl.sizeof(gl.GLfloat))
        gl.glVertexArrayAttribBinding(self.vao1[0], attribute_position, 
                                      line1_position_binding_point)
        gl.glVertexArrayAttribFormat(self.vao1[0], attribute_position, 3, 
                                     gl.GL_FLOAT, False, 0)
        gl.glEnableVertexArrayAttrib(self.vao1[0], attribute_position)

        line1_color_binding_point = 6
        gl.glVertexArrayVertexBuffer(self.vao1[0],line1_color_binding_point, 
                        self.line1_color_vbo[0],  0, 3 * gl.sizeof(gl.GLfloat))
        gl.glVertexArrayAttribBinding(self.vao1[0], attribute_color, 
                                      line1_color_binding_point)
        gl.glVertexArrayAttribFormat(self.vao1[0], attribute_color, 3, 
                                     gl.GL_FLOAT, False, 0)
        gl.glEnableVertexArrayAttrib(self.vao1[0], attribute_color)

        line2_vertices = np.array([
            # 位置          颜色
            0.0, -0.8, 0.0, 0.0, 1.0, 0.0,
            0.0, 0.8, 0.0,  0.0, 1.0, 0.0
        ], dtype=gl.GLfloat)
        self.line2_vbo = np.empty(1, dtype=gl.GLuint)
        gl.glCreateBuffers(1, self.line2_vbo)
        gl.glNamedBufferStorage(self.line2_vbo[0], line2_vertices.nbytes, 
                                line2_vertices, gl.GL_DYNAMIC_STORAGE_BIT)

        self.vao2 = np.empty(1, dtype=gl.GLuint)
        gl.glCreateVertexArrays(1, self.vao2)        
        line2_binding_point = 9
        gl.glVertexArrayVertexBuffer(self.vao2[0], line2_binding_point, 
                    self.line2_vbo[0], 0, 6 * gl.sizeof(gl.GLfloat))
        
        relativeoffset_p = 0
        gl.glVertexArrayAttribBinding(self.vao2[0], attribute_position, 
                                      line2_binding_point)
        gl.glVertexArrayAttribFormat(self.vao2[0], attribute_position, 3, 
                                     gl.GL_FLOAT, False, relativeoffset_p)
        gl.glEnableVertexArrayAttrib(self.vao2[0], attribute_position)
        relativeoffset_c = 3 * gl.sizeof(gl.GLfloat)
        gl.glVertexArrayAttribBinding(self.vao2[0], attribute_color, 
                                      line2_binding_point)
        gl.glVertexArrayAttribFormat(self.vao2[0], attribute_color, 3, 
                                     gl.GL_FLOAT, False,  relativeoffset_c)
        gl.glEnableVertexArrayAttrib(self.vao2[0], attribute_color)

        self.line_width = 2.0

    # 配置imgui界面元素
    def showImGui(self)->None:
        imgui.begin("设置")
        _, new_width = imgui.slider_float("线宽", self.line_width, 1.0, 10.0)
        self.line_width = new_width
        _, color = imgui.color_edit3("背景颜色", self.background_color.x, 
                                     self.background_color.y, 
                                     self.background_color.z)
        self.background_color = glm.vec4(color[0], color[1], color[2], 1.0)
        imgui.end()       

    # 渲染图形
    def render(self) -> None:
        gl.glClearNamedFramebufferfv(0, gl.GL_COLOR, 0, self.background_color.to_tuple())
        gl.glUseProgram(self.program)
        gl.glLineWidth(self.line_width)

        gl.glBindVertexArray(self.vao1[0])
        gl.glDrawArrays(gl.GL_LINES, 0, 2)

        gl.glBindVertexArray(self.vao2[0])
        gl.glDrawArrays(gl.GL_LINES, 0, 2)

    # 释放资源
    def cleanup(self) -> None:
        gl.glDeleteBuffers(1, self.line1_position_vbo[0])
        gl.glDeleteBuffers(1, self.line1_color_vbo[0])
        gl.glDeleteBuffers(1, self.line2_vbo[0])
        gl.glDeleteVertexArrays(1, self.vao1[0])
        gl.glDeleteVertexArrays(1, self.vao2[0])
        gl.glDeleteProgram(self.program)

if __name__ == "__main__":
    app = LineApp(100, 100, 800, 600, "你好，线段App！")
    app.run()

